名域 ts {
    /* @internal */
    导出 常量 保存是编译命令行选项: 命令行选项_ = { 名称: '保存时编译', 类型: '真假' };
    /* @internal */
    导出 常量 选项声明组: 命令行选项_[] = [
        // CommandLine only 选项组
        {
            名称: '帮助',
            短名: 'h',
            类型: '真假',
            显示在简化帮助视图: 为真,
            是命令行仅: 为真,
            诊断级别: 诊断信息_.命令行选项,
            描述: 诊断信息_.打印消息,
        },
        {
            名称: '版本',
            短名: 'v',
            类型: '真假',
            显示在简化帮助视图: 为真,
            是命令行仅: 为真,
            诊断级别: 诊断信息_.命令行选项,
            描述: 诊断信息_.打印版本,
        },
        {
            名称: '初始',
            短名: 'init',
            类型: '真假',
            显示在简化帮助视图: 为真,
            是命令行仅: 为真,
            诊断级别: 诊断信息_.命令行选项,
            描述: 诊断信息_.初始化一个_Klang_项目_同时创建_klang_json_及_klang_mod_json_配置文件,
        },
        {
            名称: '监控',
            短名: 'w',
            类型: '真假',
            参数类型: 诊断信息_.选项,
            显示在简化帮助视图: 为真,
            诊断级别: 诊断信息_.基本选项,
            描述: 诊断信息_.监控输入文件及文件改变,
        },
        {
            名称: '系统',
            短名: 'os',
            类型: 创建词典从模板({
                'win': 'win',
                'linux': 'linux',
                'darwin': 'darwin',
            }),
            参数类型: 诊断信息_.选项,
            显示在简化帮助视图: 为真,
            诊断级别: 诊断信息_.基本选项,
            描述: 诊断信息_.设置源码编译目标系统,
        },
        {
            名称: '架构',
            短名: 'arch',
            类型: 创建词典从模板({
                '368': '386',
                'amd64': 'amd64',
                'arm': 'arm'
            }),
            参数类型: 诊断信息_.选项,
            显示在简化帮助视图: 为真,
            诊断级别: 诊断信息_.基本选项,
            描述: 诊断信息_.设置源码编译目标架构,
        },
        {
            名称: '输出',
            短名: 'out',
            类型: '文字',
            参数类型: 诊断信息_.选项,
            是文件路径: 为真,
            显示在简化帮助视图: 为真,
            诊断级别: 诊断信息_.基本选项,
            描述: 诊断信息_.指定输出目录,
        },
        {
            名称: '定义',
            短名: 'env',
            类型: '列表',
            元素: {
                名称: '定义',
                短名: 'env',
                类型: '文字',
            },
            参数类型: 诊断信息_.选项,
            诊断级别: 诊断信息_.基本选项,
            描述: 诊断信息_.设置环境变量数组,
        },
    ];

    /* @internal */
    导出 接口 选项名称词典_ {
        选项名称词典: 词典_<命令行选项_>;
        短选项名称: 词典_<文字>;
    }

    变量 选项名称词典缓存: 选项名称词典_;

    函数 获取选项名称词典(): 选项名称词典_ {
        如果 (选项名称词典缓存) {
            返回 选项名称词典缓存;
        }

        常量 选项名称词典 = 创建词典<命令行选项_>();
        常量 短选项名称 = 创建词典<文字>();
        循环执行(选项声明组, 选项 => {
            选项名称词典.设置(选项.名称.转为小写(), 选项);
            如果 (选项.短名) {
                短选项名称.设置(选项.短名, 选项.名称);
            }
        });

        选项名称词典缓存 = { 选项名称词典, 短选项名称 };
        返回 选项名称词典缓存;
    }

    /* @internal */
    导出 函数 为无效自定义类型创建编译器诊断(选项: 自定义命令行选项_): 诊断_ {
        返回 为无效的自定义类型创建诊断(选项, 创建编译器诊断);
    }

    函数 为无效的自定义类型创建诊断(选项: 自定义命令行选项_, 创建诊断: (消息: 诊断信息_, 参数0: 文字, 参数1: 文字) => 诊断_): 诊断_ {
        常量 类型的名称 = 数组从(选项.类型.键组()).映射(key => `'${key}'`).连结(', ');
        返回 创建诊断(诊断信息_.Argument_for_0_option_must_be_Colon_1, `--${选项.名称}`, 类型的名称);
    }

    /* @internal */
    导出 函数 解析自定义类型选项(选项: 自定义命令行选项_, 值: 文字, 错误: 诊断_[]) {
        返回 转换自定义类型的Json选项(选项, 修剪文字(值 || ''), 错误);
    }

    /* @internal */
    导出 函数 解析列表类型选项(选项: 列表类型命令行选项_, 值 = '', 错误: 诊断_[]): (文字 | 数字)[] | 未定 {
        值 = 修剪文字(值);
        如果 (开始包含(值, '-')) {
            返回 未定;
        }
        如果 (值 === '') {
            返回 [];
        }
        常量 值组 = 值.分割(',');
        假如 (选项.元素.类型) {
            若是 '数字':
                返回 词典(值组, 编译整数);
            若是 '文字':
                返回 词典(值组, v => v || '');
            默认:
                返回 过滤器(词典(值组, v => 解析自定义类型选项(<自定义命令行选项_>选项.元素, v, 错误)!), v => !!v);
        }
    }

    导出 函数 解析命令行(命令行: 只读数组_<文字>, 读文件?: (路径: 文字) => 文字 | 未定): 解析命令行_ {
        常量 选项组: 编译选项_ = {};
        常量 错误: 诊断_[] = [];
        常量 文件名组: string[] = [];

        解析文本组(命令行);
        返回 {
            选项组,
            文件名组,
            错误,
        };

        函数 解析文本组(参数组: 只读数组_<文字>) {
            变量 i = 0;
            判断 (i < 参数组.长度) {
                常量 s = 参数组[i];
                i++;
                如果 (s.字符代码在(0) === 字符_.艾特号_) {
                    解析响应文件(s.分切(1));
                }
                否则 如果 (s.字符代码在(0) === 字符_.减号_) {
                    常量 选项 = 获取选项从名称(s.分切(s.字符代码在(1) === 字符_.减号_ ? 2 : 1), /*allowShort*/ 为真);
                    如果 (选项) {
                        如果 (选项.是仅Klang配置) {
                            错误.压入(创建编译器诊断(诊断信息_.选项_0_只支持_klang_json_配置文件, 选项.名称));
                        }
                        否则 {
                            // Check to see if no argument was provided (e.g. '--locale' is the 最后的 command-line argument).
                            如果 (!参数组[i] && 选项.类型 !== '真假') {
                                错误.压入(创建编译器诊断(诊断信息_.编译选项_0_必须为类型_1_的值, 选项.名称, '' + 选项.类型!));
                            }

                            假如 (选项.类型) {
                                若是 '数字':
                                    选项组[选项.名称] = 编译整数(参数组[i]);
                                    i++;
                                    跳出;
                                若是 '真假':
                                    // boolean flag has optional 值 true, false, others
                                    常量 选项值 = 参数组[i];
                                    选项组[选项.名称] = 选项值 !== '假';
                                    // consume next argument as boolean flag 值
                                    如果 (选项值 === '假' || 选项值 === '真') {
                                        i++;
                                    }
                                    跳出;
                                若是 '文字':
                                    选项组[选项.名称] = 参数组[i] || '';
                                    i++;
                                    跳出;
                                若是 '列表':
                                    常量 结果 = 解析列表类型选项(<列表类型命令行选项_>选项, 参数组[i], 错误);
                                    选项组[选项.名称] = 结果 || [];
                                    如果 (结果) {
                                        i++;
                                    }
                                    跳出;
                                // If not a primitive, the possible 类型组 are specified in what is effectively a map of 选项组.
                                默认:
                                    选项组[选项.名称] = 解析自定义类型选项(<自定义命令行选项_>选项, 参数组[i], 错误);
                                    i++;
                                    跳出;
                            }
                        }
                    }
                    否则 {
                        错误.压入(创建编译器诊断(诊断信息_.未知命令行选项_0, s));
                    }
                }
                否则{
                    文件名组.压入(s)
                }
            }
        }

        函数 解析响应文件(文件名: 文字) {
            常量 文本 = 读文件 ? 读文件(文件名) : sys.读文件(文件名);

            如果 (!文本) {
                错误.压入(创建编译器诊断(诊断信息_.没发现文件_0, 文件名));
                返回;
            }

            常量 实参组: 文字[] = [];
            变量 首位 = 0;
            判断 (为真) {
                判断 (首位 < 文本.长度 && 文本.字符代码在(首位) <= 字符_.空格_) 首位++;
                如果 (首位 >= 文本.长度) 跳出;
                常量 开始 = 首位;
                如果 (文本.字符代码在(开始) === 字符_.双引号_) {
                    首位++;
                    判断 (首位 < 文本.长度 && 文本.字符代码在(首位) !== 字符_.双引号_) 首位++;
                    如果 (首位 < 文本.长度) {
                        实参组.压入(文本.子文字(开始 + 1, 首位));
                        首位++;
                    }
                    否则 {
                        错误.压入(创建编译器诊断(诊断信息_.响应文件_0_中有未中止文本引用, 文件名));
                    }
                }
                否则 {
                    判断 (文本.字符代码在(首位) > 字符_.空格_) 首位++;
                    实参组.压入(文本.子文字(开始, 首位));
                }
            }
            解析文本组(实参组);
        }
    }

    函数 获取选项从名称(选项名称: 文字, 允许短名 = 为假): 命令行选项_ | 未定 {
        选项名称 = 选项名称.转为小写();
        常量 { 选项名称词典, 短选项名称 } = 获取选项名称词典();
        // Try to translate short option names to their full equivalents.
        如果 (允许短名) {
            常量 短名 = 短选项名称.获取(选项名称);
            如果 (短名 !== 未定) {
                选项名称 = 短名;
            }
        }
        返回 选项名称词典.获取(选项名称);
    }

    函数 命令行选项转为词典(选项组: 只读数组_<命令行选项_>) {
        返回 转为词典(选项组, 选项 => 选项.名称);
    }

    函数 获取编译选项值类型文字(选项: 命令行选项_) {
        返回 选项.类型 === '列表' ?
            '数组_' :
            是文字(选项.类型) ? 选项.类型 : '文字';
    }

    函数 是命令行选项值(选项: 命令行选项_, 值: 任意): 值 作为 编译选项值_ {
        如果 (选项) {
            如果 (是空或未定义(值)) 返回 为真; // All 选项组 are undefinable/nullable
            如果 (选项.类型 === '列表') {
                返回 是数组(值);
            }
            假如 (选项.类型) {
                若是 '对象':
                    返回 类为 值 === '对象';
                若是 '文字':
                    返回 类为 值 === '文字';
                若是 '数字':
                    返回 类为 值 === '数字';
                若是 '真假':
                    返回 类为 值 === '真假';
                默认:
                    返回 类为 值 === '文字';
            }
        }
        返回 为真;
    }

    导出 函数 生成KLang_mod(): 文字 {
        常量 选项组 = {
            名称: 'klangApp',
            版本: '0.0.1',
            主页: 'gitee.com/xxx/xxxx',
            作者: {
                姓名: 'Xxxx',
                邮箱: 'Xxxx@xx.com'
            },
            依赖: {}
        }
        返回 JSON.序列化(选项组, 未定, 4);
    }

    导出 函数 生成KLang(): 文字 {
        常量 默认值 = {
            系统: 'win',
            架构: 'amd64',
            输出: './输出',
            监控: 为真,
            启用诊断: 为真,
            定义: []
        }
        返回 JSON.序列化(默认值, 未定, 4);
    }

    函数 是空或未定义(x: 任意): x 作为 空值 | 未定 {
        // tslint:disable-next-line:no-null-keyword
        返回 x === 未定 || x === 空值;
    }

    /*@internal*/
    导出 函数 是错误在输入文件(错误: 诊断_) {
        返回 错误.代码 === 诊断信息_.在输入文件_0_找不到指定文件.代码;
    }

    /*@internal*/
    导出 函数 获取错误从输入文件(配置文件名称: 文字 | 未定) {
        返回 创建编译器诊断( 诊断信息_.在输入文件_0_找不到指定文件, 配置文件名称 || 'kconfig.json');
    }


    导出 函数 转换命令行选项从Json(json选项: 任意, 基路径: 文字, 配置文件名称?: 文字): { 选项组: 编译选项_, 错误: 诊断_[] } {
        常量 错误: 诊断_[] = [];
        常量 选项组 = 转换命令行选项从json平台(json选项, 基路径, 错误, 配置文件名称);
        返回 { 选项组, 错误 };
    }

    函数 获取默认编译选项(配置文件名称?: 文字) {
        常量 选项组: 编译选项_ = 获取基文件名称(配置文件名称!) === 'kconfig.json'
            ? { 系统: 'win', 架构: 'amd64', 定义: ['__win__'], 输出: './输出' 转为 路径_ }
            : {};
        返回 选项组;
    }

    函数 转换命令行选项从json平台(json选项: 任意, 基路径: 文字, 错误: 诊断_[], 配置文件名称?: 文字): 编译选项_ {
        常量 选项组 = 获取默认编译选项(配置文件名称);
        转换选项从Json(选项声明组, json选项, 基路径, 选项组, 诊断信息_.未知命令行选项_0, 错误);
        返回 选项组;
    }


    函数 转换选项从Json(选项声明: 只读数组_<命令行选项_>, json选项: 任意, 基路径: 文字, 默认选项: 编译选项_, 诊断信息: 诊断信息_, 错误: 诊断_[]) {
        如果 (!json选项) {
            返回;
        }

        常量 选项名称词典 = 命令行选项转为词典(选项声明);

        循环 (常量 id 位于 json选项) {
            常量 选项 = 选项名称词典.获取(id);
            如果 (选项) {
                默认选项[选项.名称] = 转换Json选项(选项, json选项[id], 基路径, 错误);
            }
            否则 {
                错误.压入(创建编译器诊断(诊断信息, id));
            }
        }
    }

    函数 转换Json选项(选项: 命令行选项_, 值: 任意, 基路径: 文字, 错误: 诊断_[]): 编译选项值_ {
        如果 (是命令行选项值(选项, 值)) {
            常量 选项类型 = 选项.类型;
            如果 (选项类型 === '列表' && 是数组(值)) {
                返回 转换列表类型的Json选项(<列表类型命令行选项_>选项, 值, 基路径, 错误);
            }
            否则 如果 (!是文字(选项类型)) {
                返回 转换自定义类型的Json选项(<自定义命令行选项_>选项, <文字>值, 错误);
            }
            返回 规范化非列表选项值(选项, 基路径, 值);
        }
        否则 {
            错误.压入(创建编译器诊断(诊断信息_.编译选项_0_必须为类型_1_的值, 选项.名称, 获取编译选项值类型文字(选项)));
        }
    }

    函数 规范化非列表选项值(选项: 命令行选项_, 基路径: 文字, 值: 任意): 编译选项值_ {
        如果 (选项.是文件路径) {
            值 = 正规化路径(合并路径(基路径, 值));
            如果 (值 === '') {
                值 = '.';
            }
        }
        返回 值;
    }

    函数 转换自定义类型的Json选项(选项: 自定义命令行选项_, 值: 文字, 错误: 诊断_[]) {
        如果 (是空或未定义(值)) 返回 未定;
        常量 键 = 值.转为小写();
        常量 选项值 = 选项.类型.获取(键);
        如果 (选项值 !== 未定) {
            返回 选项值;
        }
        否则 {
            错误.压入(为无效自定义类型创建编译器诊断(选项));
        }
    }

    函数 转换列表类型的Json选项(选项: 列表类型命令行选项_, 值组: 只读数组_<任意>, 基路径: 文字, 错误: 诊断_[]): 任意[] {
        返回 过滤器(词典(值组, v => 转换Json选项(选项.元素, v, 基路径, 错误)), v => !!v);
    }

    函数 修剪文字(s: 文字) {
        返回 类为 s.修剪 === '函数' ? s.修剪() : s.替换(/^[\s]+|[\s]+$/g, '');
    }

    导出 函数 转换命令行选项从模板(选项: 编译选项_): 编译选项_ {
        常量 输出: 编译选项_ = {};
        循环 (常量 键 位于 选项) {
            如果 (实例_.原型.具有本身属性.调用(选项, 键)) {
                常量 类型 = 获取选项从名称(键);
                如果 (类型 !== 未定) { // Ignore unknown 选项组
                    输出[键] = 获取选项值包括空文本(选项[键], 类型);
                }
            }
        }
        返回 输出;
    }

    函数 获取选项值包括空文本(值: 任意, 选项: 命令行选项_): {} {
        假如 (选项.类型) {
            若是 '对象': // 'paths'. Can't get any useful information from the 值 since we blank out strings, so just return ''.
                返回 '';
            若是 '文字': // Could be any arbitrary string -- use empty string instead.
                返回 '';
            若是 '数字': // Allow numbers, but be sure to check it's actually a number.
                返回 类为 值 === '数字' ? 值 : '';
            若是 '真假':
                返回 类为 值 === '真假' ? 值 : '';
            若是 '列表':
                常量 元素类型 = (选项 转为 列表类型命令行选项_).元素;
                返回 是数组(值) ? 值.映射(v => 获取选项值包括空文本(v, 元素类型)) : '';
            默认:
                返回 循环每个(选项.类型, (选项枚举值, 选项文本值) => {
                    如果 (选项枚举值 === 值) {
                        返回 选项文本值;
                    }
                })!;
        }
    }
}
